package com.uqbar.asteroids.components;

import java.awt.Color;
import java.awt.Graphics2D;






import com.uqbar.asteroids.scenes.AsteroidScene;
import com.uqbar.vainilla.DeltaState;
import com.uqbar.vainilla.GameComponent;
import com.uqbar.vainilla.GameScene;
import com.uqbar.vainilla.appearances.Circle;
import com.uqbar.vainilla.appearances.Sprite;
import com.uqbar.vainilla.events.constants.Key;

public abstract class PlayerShip extends GameComponent<AsteroidScene>{
	 private double speed;
	 private int live;
	 private int defense;
	 private int radio;
	 private int xMin, yMin=0;
	 private int xMax;
     private int yMax;
     private Vector2D velocidadPolar = new Vector2D(0, -1.57);
     private double anguloCanion = 0;
     private int rapidezDisparo = 100;
     
 	
 	public double getAnguloCanion() {
		return anguloCanion;
	}
 	
 	public double cannonSize() {
		return this.getRadio() * 2;
	}

	public void setAnguloCanion(double anguloCanion) {
		this.anguloCanion = anguloCanion;
	}


	private Vector2D getPosition() {
 		return new Vector2D(this.getX(), this.getY());
 	}
     
     
    public Vector2D getVelocidadPolar() {
		return velocidadPolar;
	}

	public void setVelocidadPolar(Vector2D velocidadPolar) {
		this.velocidadPolar = velocidadPolar;
	}

	public double getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getLive() {
		return live;
	}

	public void setLive(int live) {
		this.live = live;
	}

	public int getDefense() {
		return defense;
	}

	public void setDefense(int defense) {
		this.defense = defense;
	}

	public int getRadio() {
		return radio;
	}

	public void setRadio(int radio) {
		this.radio = radio;
	}

	public int getxMin() {
		return xMin;
	}

	public void setxMin(int xMin) {
		this.xMin = xMin;
	}

	public int getyMin() {
		return yMin;
	}

	public void setyMin(int yMin) {
		this.yMin = yMin;
	}

	public int getxMax() {
		return xMax;
	}

	public void setxMax(int xMax) {
		this.xMax = xMax;
	}

	public int getyMax() {
		return yMax;
	}

	public void setyMax(int yMax) {
		this.yMax = yMax;
	}

	public PlayerShip(int speed, int live, int defense, int radio, double intiPosX, double initPosY){
    	 this.setAppearance(new Circle(Color.BLACK,radio));
    	 this.setY(initPosY);
    	 this.setX(intiPosX);
    	 this.live =live;
    	 this.defense = defense;
    	 this.radio = radio;
    	 this.speed = speed;
     }
	
//	public double arriba(DeltaState delta) {
//		return 5 * delta.getDelta();
//		
//	}
//	
//	public void derecha(double delta) {
//		this.setX(Math.min(getxMax() - this.getAppearance().getWidth(), this.getX()+getSpeed()*delta));
//	}
//	
//	public void arriba(double delta){
//		this.setY(Math.max(this.getY()-getSpeed()*delta, getxMin()));
//	}
//	
//	public double abajo(DeltaState delta, double ro){
//		return Math.max(0, ro - (5 * delta.getDelta()));
//	}
	
	public void onSceneActivated(){	
	  super.onSceneActivated();
    }
	
//	@Override
//	public void update(DeltaState deltaState) {
//		actualizarVelocidad(deltaState);
//		actualizarPosicion(deltaState.getDelta());
//
//	}

	public void actualizarVelocidad(DeltaState deltaState) {
		double deltaSpeed = 25;

		double ro = velocidadPolar.getX();
		double theta = velocidadPolar.getY();

		if (deltaState.isKeyBeingHold(Key.UP)) {
			ro += deltaSpeed * deltaState.getDelta();
		} else if (deltaState.isKeyBeingHold(Key.DOWN)) {
			ro = Math.max(0, ro - (deltaSpeed * deltaState.getDelta()));
		} else if (deltaState.isKeyBeingHold(Key.RIGHT)) {
			theta = theta + (getVelocidadAngular() * deltaState.getDelta());
			theta = ajustarAnguloEntrePiYMenosPi(theta);
			double heta = anguloCanion - this.getVelocidadAngular() * deltaState.getDelta();
			anguloCanion = this.ajustarAnguloEntrePiYMenosPi(heta);	
			Sprite i = this.getScene().getSkinShip().getImage().rotate(50);
			this.getScene().getSkinShip().setImage(i);
		} else if (deltaState.isKeyBeingHold(Key.LEFT)) {
			theta = theta - (getVelocidadAngular() * deltaState.getDelta());
			theta = ajustarAnguloEntrePiYMenosPi(theta);
			double thet = anguloCanion + this.getVelocidadAngular() * deltaState.getDelta();
			anguloCanion = this.ajustarAnguloEntrePiYMenosPi(thet);
		}
		if (deltaState.isKeyPressed(Key.SPACE)) {
			shoot();
		}
		velocidadPolar = new Vector2D(ro, theta);
	}
	
	//cuantos grados por segundo va a girar
	public double getVelocidadAngular() {
		return Math.PI; // media vuelta por segundo
	}
	
	//TODO, asi como está solo sirve si me pasé una vuelta sola, por eso 
	//solo se puede usar en el caso que el delta aplicado sobre el angulo
	//sean menor a 2*PI.
	//Lo que hace el metodo es quitar o sumar 2*PI para que quede en el angulo en ese radio
	public double ajustarAnguloEntrePiYMenosPi(double theta) {
		theta = theta > getVelocidadAngular() ? theta - 2 * getVelocidadAngular() : theta;
		theta = theta < -getVelocidadAngular() ? theta + 2 * getVelocidadAngular() : theta;
		return theta;
	}
	
	@Override
	public void render(Graphics2D graphics) {
		super.render(graphics);
//		renderVelocity(graphics);
	}
	
	public void actualizarPosicion1(double delta) {

		Vector2D cartesianPosition = getPosition().suma(
				getVelocidadPolar().toCartesians().producto(delta));
		
		setXVisible(cartesianPosition.getX());
		setYVisible(cartesianPosition.getY());
	}
	
	private void setYVisible(double yCartesiano) {
		if (yCartesiano > 0
				&& yCartesiano < this.getGame().getDisplayHeight() - this.getDiametro()) {
			this.setY(yCartesiano);
		}
	}

	private void setXVisible(double xCartesiano) {
		if (xCartesiano > 0
				&& xCartesiano < this.getGame().getDisplayWidth() - this.getDiametro()) {
			this.setX(xCartesiano);
		}
	}

	protected Vector2D getCentro() {
		return new Vector2D(this.getX() + this.getDiametro() / 2, this.getY() + this.getDiametro()
				/ 2);
	}
	protected double getRapidezDisparo() {
		return rapidezDisparo;
	}
	
	public int getDiametro(){
		return this.getRadio()*2;
	}
	public void coordinarImagen(){
		  this.getScene().getSkinShip().setX(this.getX()-26);
		  this.getScene().getSkinShip().setY(this.getY()-20);
	}
	
	private Vector2D puntaCanion() {
		Vector2D polarCanionPosition = new Vector2D(this.getDiametro(), this.getVelocidadPolar().getY() + this.anguloCanion); 
		Vector2D cartesianCanionPosition = polarCanionPosition.toCartesians();
		return cartesianCanionPosition.suma(this.getCentro());
	}
	
	
	

	protected Vector2D getOrigenDisparo() {
		return puntaCanion();
	}
	

	protected Vector2D getVelocidadBala() {
		return this.getVelocidadPolar().suma(new Vector2D(this.getRapidezDisparo(), this.anguloCanion))
				.toCartesians();
	}
	
	protected void shoot() {
		Vector2D centro = getOrigenDisparo();
		Bala<GameScene> bala = new Bala<GameScene>(centro.getX(),
				centro.getY(),
				getVelocidadBala());
		
		this.getScene().addComponent(bala);
	}
	
	@Override
	public void update(DeltaState deltaState) {
		
		Vector2D posicionPropuesta = this.getPosition().suma(this.getVelocidadPolar().producto(deltaState.getDelta()));
		actualizarPosicion(posicionPropuesta);
		
		actualizarVelocidad(deltaState);
		actualizarPosicion1(deltaState.getDelta());

		if(deltaState.isKeyBeingHold(Key.RIGHT)) {
			double theta = anguloCanion + this.getVelocidadAngular() * deltaState.getDelta();
			anguloCanion = this.ajustarAnguloEntrePiYMenosPi(theta);
		}
		if(deltaState.isKeyBeingHold(Key.LEFT)) {
			double theta = anguloCanion - this.getVelocidadAngular() * deltaState.getDelta();
			anguloCanion = this.ajustarAnguloEntrePiYMenosPi(theta);			
		}
		
		
		
	}
	
	private void actualizarPosicion(Vector2D posicionPropuesta) {
		
		double x = posicionPropuesta.getX();
		double y = posicionPropuesta.getY();
		
		if (x + this.getDiametro() <= 0) {
			x = this.getGame().getDisplayWidth();
		} else if (x >= this.getGame().getDisplayWidth()) {
			x = -this.getDiametro();
		}
		
		if (y <= 0) {
			y = this.getGame().getDisplayHeight();
		} else if (y >= this.getGame().getDisplayHeight()) {
			y = -this.getDiametro();
		}
		this.setX(x);
		this.setY(y);
		
	}
//	public abstract void shoot();

}
